/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    dead_code,
    non_upper_case_globals,
    unused_assignments,
    unused_mut,
    unused_variables,
    clippy::eq_op
)]

use libc::EXIT_FAILURE;
use std::ffi::CStr;

#[macro_use]
mod common;
use crate::common::alias as alias_struct;
use crate::common::defaults as defaults_struct;
use crate::common::*;

mod alias;
mod audit;
mod base64;
mod defaults;
mod digestname;
mod editor;
mod filedigest;
mod find_path;
mod gentime;
mod gmtoff;
mod goodpath;
mod gram;
mod hexchar;
mod linux_audit;
mod locale;
mod logging;
mod logwrap;
mod r#match;
mod match_addr;
mod match_command;
mod match_digest;
mod pwutil;
mod pwutil_impl;
mod rcstr;
mod redblack;
mod set_perms;
mod stubs;
mod sudo_printf;
mod sudoers_debug;
mod timeout;
mod timestr;
mod toke;
mod toke_util;

pub const kernel: libc::c_uint = 9;
pub const tty: libc::c_uint = 8;
pub const ppid: libc::c_uint = 7;
pub const global: libc::c_uint = 6;
pub const digest_only: libc::c_uint = 5;
pub const all: libc::c_uint = 4;
pub const any: libc::c_uint = 3;
pub const always: libc::c_uint = 2;
pub const once: libc::c_uint = 1;
pub const never: libc::c_uint = 0;
pub const no_argument: libc::c_int = 0;
pub const required_argument: libc::c_int = 1;
pub const ALIAS: libc::c_int = 258;
pub const HOSTALIAS: libc::c_int = 286;
pub const CMNDALIAS: libc::c_int = 287;
pub const USERALIAS: libc::c_int = 288;
pub const RUNASALIAS: libc::c_int = 289;
pub const SUDO_TLOCK: libc::c_int = 2;

pub const SETDEF_GENERIC: libc::c_int = 0x01;
pub const SETDEF_HOST: libc::c_int = 0x02;
pub const SETDEF_USER: libc::c_int = 0x04;
pub const SETDEF_RUNAS: libc::c_int = 0x08;
pub const SETDEF_CMND: libc::c_int = 0x10;
pub const EXDEV: libc::c_int = 18;

#[macro_export]
macro_rules! _PATH_MV {
    () => {
        b"/usr/bin/mv\0" as *const u8 as *const libc::c_char
    };
}

#[link(name = "audit")]
#[link(name = "utsudo_util")]
#[link(name = "util_variadic")]
#[link(name = "plugins_variadic")]
extern "C" {
    fn chmod(__file: *const libc::c_char, __mode: __mode_t) -> libc::c_int;
    fn utimensat(
        __fd: libc::c_int,
        __path: *const libc::c_char,
        __times: *const timespec,
        __flags: libc::c_int,
    ) -> libc::c_int;
    fn stat(path:*const libc::c_char,buf:*mut stat) -> libc::c_int;
    fn fstat(filedes:libc::c_int,buf:*mut stat) -> libc::c_int;
    fn writev(__fd: libc::c_int, __iovec: *const iovec, __count: libc::c_int) -> ssize_t;
    fn open(__file: *const libc::c_char, __oflag: libc::c_int, _: ...) -> libc::c_int;
    fn sigemptyset(__set: *mut sigset_t) -> libc::c_int;
    fn sigaction(
        __sig: libc::c_int,
        __act: *const sigaction,
        __oact: *mut sigaction,
    ) -> libc::c_int;
    fn waitpid(__pid: __pid_t, __stat_loc: *mut libc::c_int, __options: libc::c_int) -> __pid_t;
    fn fclose(__stream: *mut FILE) -> libc::c_int;
    fn fopen(_: *const libc::c_char, _: *const libc::c_char) -> *mut FILE;
    fn fdopen(__fd: libc::c_int, __modes: *const libc::c_char) -> *mut FILE;
    fn fprintf(_: *mut FILE, _: *const libc::c_char, _: ...) -> libc::c_int;
    fn printf(_: *const libc::c_char, _: ...) -> libc::c_int;
    fn snprintf(
        _: *mut libc::c_char,
        _: libc::c_ulong,
        _: *const libc::c_char,
        _: ...
    ) -> libc::c_int;
    fn asprintf(__ptr: *mut *mut libc::c_char, __fmt: *const libc::c_char, _: ...) -> libc::c_int;
    fn getc(__stream: *mut FILE) -> libc::c_int;
    fn fputc(__c: libc::c_int, __stream: *mut FILE) -> libc::c_int;
    static mut stderr: *mut FILE;
    fn fputs(__s: *const libc::c_char, __stream: *mut FILE) -> libc::c_int;
    fn puts(__s: *const libc::c_char) -> libc::c_int;
    fn rewind(__stream: *mut FILE);
    static mut stdout: *mut FILE;
    static mut stdin: *mut FILE;
    fn rename(__old: *const libc::c_char, __new: *const libc::c_char) -> libc::c_int;
    fn calloc(_: libc::c_ulong, _: libc::c_ulong) -> *mut libc::c_void;
    fn reallocarray(__ptr: *mut libc::c_void, __nmemb: size_t, __size: size_t)
        -> *mut libc::c_void;
    fn free(_: *mut libc::c_void);
    fn exit(_: libc::c_int) -> !;
    fn getenv(__name: *const libc::c_char) -> *mut libc::c_char;
    fn memset(_: *mut libc::c_void, _: libc::c_int, _: libc::c_ulong) -> *mut libc::c_void;
    fn strcmp(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_int;
    fn strncmp(_: *const libc::c_char, _: *const libc::c_char, _: libc::c_ulong) -> libc::c_int;
    fn strdup(_: *const libc::c_char) -> *mut libc::c_char;
    fn strndup(_: *const libc::c_char, _: libc::c_ulong) -> *mut libc::c_char;
    fn strrchr(_: *const libc::c_char, _: libc::c_int) -> *mut libc::c_char;
    fn strlen(_: *const libc::c_char) -> libc::c_ulong;
    fn strsignal(__sig: libc::c_int) -> *mut libc::c_char;
    fn lseek(__fd: libc::c_int, __offset: __off_t, __whence: libc::c_int) -> __off_t;
    fn close(__fd: libc::c_int) -> libc::c_int;
    fn read(__fd: libc::c_int, __buf: *mut libc::c_void, __nbytes: size_t) -> ssize_t;
    fn write(__fd: libc::c_int, __buf: *const libc::c_void, __n: size_t) -> ssize_t;
    fn chown(__file: *const libc::c_char, __owner: __uid_t, __group: __gid_t) -> libc::c_int;
    fn execv(__path: *const libc::c_char, __argv: *const *mut libc::c_char) -> libc::c_int;
    fn execlp(__file: *const libc::c_char, __arg: *const libc::c_char, _: ...) -> libc::c_int;
    fn _exit(_: libc::c_int) -> !;
    fn getuid() -> __uid_t;
    fn geteuid() -> __uid_t;
    fn unlink(__name: *const libc::c_char) -> libc::c_int;
    static mut optarg: *mut libc::c_char;
    static mut optind: libc::c_int;
    fn __ctype_tolower_loc() -> *mut *const __int32_t;
    fn __errno_location() -> *mut libc::c_int;
    fn alloc_aliases() -> *mut rbtree;
    fn free_aliases(aliases: *mut rbtree);
    fn no_aliases(parse_tree: *mut sudoers_parse_tree) -> bool;
    fn alias_type_to_string(alias_type: libc::c_int) -> *const libc::c_char;
    fn alias_get(
        parse_tree: *mut sudoers_parse_tree,
        name: *const libc::c_char,
        type_0: libc::c_int,
    ) -> *mut alias_struct;
    fn alias_find_used(parse_tree: *mut sudoers_parse_tree, used_aliases: *mut rbtree) -> bool;
    fn alias_apply(
        parse_tree: *mut sudoers_parse_tree,
        func: Option<
            unsafe extern "C" fn(
                *mut sudoers_parse_tree,
                *mut alias_struct,
                *mut libc::c_void,
            ) -> libc::c_int,
        >,
        cookie: *mut libc::c_void,
    );
    fn alias_put(a: *mut alias_struct);
    static mut parsed_policy: sudoers_parse_tree;
    fn init_parser(path: *const libc::c_char, quiet: bool) -> bool;
    fn sudoers_warn_setlocale(restore: bool, cookie: *mut libc::c_int) -> bool;
    fn sudoers_setlocale(newlocale: libc::c_int, prevlocale: *mut libc::c_int) -> bool;
    fn sudoers_initlocale(ulocale: *const libc::c_char, slocale: *const libc::c_char) -> bool;
    fn sudoers_locale_callback(_: *const sudo_defs_val) -> bool;
    fn check_defaults(parse_tree: *mut sudoers_parse_tree, quiet: bool) -> bool;
    fn update_defaults(
        parse_tree: *mut sudoers_parse_tree,
        defs: *mut defaults_list,
        what: libc::c_int,
        quiet: bool,
    ) -> bool;
    fn init_defaults() -> bool;
    fn sudo_conf_read_v1(conf_file: *const libc::c_char, conf_types: libc::c_int) -> libc::c_int;
    fn sudo_conf_debug_files_v1(progname: *const libc::c_char) -> *mut sudo_conf_debug_file_list;
    fn sudo_conf_plugins_v1() -> *mut plugin_info_list;
    fn sudo_gettime_real_v1(ts: *mut timespec) -> libc::c_int;
    fn sudo_lock_file_v1(fd: libc::c_int, action: libc::c_int) -> bool;
    fn initprogname(_: *const libc::c_char);
    fn sudo_strsplit_v1(
        str: *const libc::c_char,
        endstr: *const libc::c_char,
        sep: *const libc::c_char,
        last: *mut *const libc::c_char,
    ) -> *const libc::c_char;
    fn sudo_strtoid_v2(str: *const libc::c_char, errstr: *mut *const libc::c_char) -> id_t;
    fn sudo_strtomode_v1(cp: *const libc::c_char, errstr: *mut *const libc::c_char) -> libc::c_int;
    fn sudo_debug_exit_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        subsys: libc::c_int,
    );
    fn sudo_debug_exit_bool_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        subsys: libc::c_int,
        ret: bool,
    );
    fn sudo_debug_exit_int_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        subsys: libc::c_int,
        ret: libc::c_int,
    );
    fn sudo_debug_exit_ptr_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        subsys: libc::c_int,
        ret: *const libc::c_void,
    );
    fn sudo_debug_exit_str_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        subsys: libc::c_int,
        ret: *const libc::c_char,
    );
    fn sudo_debug_fork_v1() -> pid_t;
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    static mut sudoers_subsystem_ids: [libc::c_uint; 0];
    fn sudoersparse() -> libc::c_int;
    static mut errorfile: *mut libc::c_char;
    static mut errorlineno: libc::c_int;
    static mut parse_error: bool;
    static mut sudoersin: *mut FILE;
    static mut sudoers_file: *const libc::c_char;
    static mut sudoers: *mut libc::c_char;
    static mut sudoers_mode: mode_t;
    static mut sudoers_uid: uid_t;
    static mut sudoers_gid: gid_t;
    fn sudo_getpwnam(_: *const libc::c_char) -> *mut passwd;
    fn sudo_getpwuid(_: uid_t) -> *mut passwd;
    static mut sudo_defs_table: [sudo_defs_types; 0];
    fn setlocale(__category: libc::c_int, __locale: *const libc::c_char) -> *mut libc::c_char;
    fn textdomain(__domainname: *const libc::c_char) -> *mut libc::c_char;
    fn bindtextdomain(
        __domainname: *const libc::c_char,
        __dirname: *const libc::c_char,
    ) -> *mut libc::c_char;
    fn sudo_closefrom(_: libc::c_int);
    fn sudo_warnx_nodebug_v1(fmt: *const libc::c_char, _: ...);
    fn sudo_warn_nodebug_v1(fmt: *const libc::c_char, _: ...);
    fn sudo_getprogname() -> *const libc::c_char;
    fn sudo_fatal_callback_register_v1(func: sudo_fatal_callback_t) -> libc::c_int;
    fn sudo_warn_gettext_v1(
        domainname: *const libc::c_char,
        msgid: *const libc::c_char,
    ) -> *mut libc::c_char;
    fn sudo_warn_set_locale_func_v1(
        func: Option<unsafe extern "C" fn(bool, *mut libc::c_int) -> bool>,
    );
    fn sudo_fatal_nodebug_v1(fmt: *const libc::c_char, _: ...) -> !;
    fn sudo_fatalx_nodebug_v1(fmt: *const libc::c_char, _: ...) -> !;
    fn sudoers_debug_register(
        plugin_path: *const libc::c_char,
        debug_files: *mut sudo_conf_debug_file_list,
    ) -> bool;
    fn find_editor(
        nfiles: libc::c_int,
        files: *mut *mut libc::c_char,
        argc_out: *mut libc::c_int,
        argv_out: *mut *mut *mut libc::c_char,
        whitelist: *const *mut libc::c_char,
        env_editor: *mut *const libc::c_char,
        env_error: bool,
    ) -> *mut libc::c_char;
    fn rcstr_dup(src: *const libc::c_char) -> *mut libc::c_char;
    fn rcstr_addref(s: *const libc::c_char) -> *mut libc::c_char;
    fn rcstr_delref(s: *const libc::c_char);
    fn getopt_long(
        ___argc: libc::c_int,
        ___argv: *const *mut libc::c_char,
        __shortopts: *const libc::c_char,
        __longopts: *const option,
        __longind: *mut libc::c_int,
    ) -> libc::c_int;
    fn get_hostname();
    fn sudoersrestart(_: *mut FILE);
}

#[derive(Copy, Clone, BitfieldStruct)]
#[repr(C)]
pub struct cmndtag {
    #[bitfield(name = "nopasswd", ty = "libc::c_int", bits = "0..=2")]
    #[bitfield(name = "noexec", ty = "libc::c_int", bits = "3..=5")]
    #[bitfield(name = "setenv", ty = "libc::c_int", bits = "6..=8")]
    #[bitfield(name = "log_input", ty = "libc::c_int", bits = "9..=11")]
    #[bitfield(name = "log_output", ty = "libc::c_int", bits = "12..=14")]
    #[bitfield(name = "send_mail", ty = "libc::c_int", bits = "15..=17")]
    #[bitfield(name = "follow", ty = "libc::c_int", bits = "18..=20")]
    pub nopasswd_noexec_setenv_log_input_log_output_send_mail_follow: [u8; 3],
    #[bitfield(padding)]
    pub c2rust_padding: [u8; 1],
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudoersfile {
    pub entries: C2RustUnnamed_19,
    pub path: *mut libc::c_char,
    pub tpath: *mut libc::c_char,
    pub modified: bool,
    pub doedit: bool,
    pub fd: libc::c_int,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct C2RustUnnamed_19 {
    pub tqe_next: *mut sudoersfile,
    pub tqe_prev: *mut *mut sudoersfile,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudoersfile_list {
    pub tqh_first: *mut sudoersfile,
    pub tqh_last: *mut *mut sudoersfile,
}

// #define MATCHES(s, v)	\
//     (strncmp((s), (v), sizeof(v) - 1) == 0 && (s)[sizeof(v) - 1] != '\0')
macro_rules! MATCHES_VISUDO {
    ($s:expr, $v:expr, $len:expr) => {
        strncmp(
            $s,
            $v as *const u8 as *const libc::c_char,
            (::core::mem::size_of::<[libc::c_char; $len]>() as libc::c_ulong)
                .wrapping_sub(1 as libc::c_int as libc::c_ulong),
        ) == 0 as libc::c_int
            && *($s).offset(
                (::core::mem::size_of::<[libc::c_char; $len]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong) as isize,
            ) as libc::c_int
                != '\0' as i32
    };
}

#[inline]
fn getchar() -> libc::c_int {
    unsafe { getc(stdin) }
}
#[inline]
fn tolower(mut __c: libc::c_int) -> libc::c_int {
    if __c >= -(128 as libc::c_int) && __c < 256 as libc::c_int {
        unsafe { *(*__ctype_tolower_loc()).offset(__c as isize) }
    } else {
        __c
    }
}
/*
 * Globals
 */
#[no_mangle]
pub static mut sudo_user: sudo_user = sudo_user {
    pw: 0 as *const passwd as *mut passwd,
    _runas_pw: 0 as *const passwd as *mut passwd,
    _runas_gr: 0 as *const group as *mut group,
    cmnd_stat: 0 as *const stat as *mut stat,
    name: 0 as *const libc::c_char as *mut libc::c_char,
    path: 0 as *const libc::c_char as *mut libc::c_char,
    tty: 0 as *const libc::c_char as *mut libc::c_char,
    ttypath: 0 as *const libc::c_char as *mut libc::c_char,
    host: 0 as *const libc::c_char as *mut libc::c_char,
    shost: 0 as *const libc::c_char as *mut libc::c_char,
    runhost: 0 as *const libc::c_char as *mut libc::c_char,
    srunhost: 0 as *const libc::c_char as *mut libc::c_char,
    prompt: 0 as *const libc::c_char as *mut libc::c_char,
    cmnd: 0 as *const libc::c_char as *mut libc::c_char,
    cmnd_args: 0 as *const libc::c_char as *mut libc::c_char,
    cmnd_base: 0 as *const libc::c_char as *mut libc::c_char,
    cmnd_safe: 0 as *const libc::c_char as *mut libc::c_char,
    class_name: 0 as *const libc::c_char as *mut libc::c_char,
    krb5_ccname: 0 as *const libc::c_char as *mut libc::c_char,
    gid_list: 0 as *const gid_list as *mut gid_list,
    env_vars: 0 as *const *mut libc::c_char,
    role: 0 as *const libc::c_char as *mut libc::c_char,
    type_0: 0 as *const libc::c_char as *mut libc::c_char,
    cwd: 0 as *const libc::c_char,
    iolog_file: 0 as *const libc::c_char as *mut libc::c_char,
    gids: 0 as *const gid_t as *mut gid_t,
    execfd: 0,
    ngids: 0,
    closefrom: 0,
    lines: 0,
    cols: 0,
    flags: 0,
    max_groups: 0,
    timeout: 0,
    umask: 0,
    uid: 0,
    gid: 0,
    sid: 0,
};
#[no_mangle]
pub static mut list_pw: *mut passwd = 0 as *const passwd as *mut passwd;
static mut sudoerslist: sudoersfile_list = sudoersfile_list {
    tqh_first: 0 as *const sudoersfile as *mut sudoersfile,
    tqh_last: 0 as *const *mut sudoersfile as *mut *mut sudoersfile,
};
static mut checkonly: bool = false;
static mut short_opts: [libc::c_char; 10] =
    unsafe { *::core::mem::transmute::<&[u8; 10], &[libc::c_char; 10]>(b"cf:hqsVx:\0") };

#[macro_export]
macro_rules! long_optsNew {
    ($name:expr, $has_arg:expr, $flag:expr, $val:expr) => {
        option {
            name: $name as *const u8 as *const libc::c_char as *mut libc::c_char,
            has_arg: $has_arg as libc::c_int,
            flag: $flag as *const libc::c_int as *mut libc::c_int,
            val: $val as i32,
        }
    };
}

static mut long_opts: [option; 8] = [
    {
        long_optsNew!(b"check\0", no_argument, 0, 'c')
        //init
    },
    {
        long_optsNew!(b"export\0", required_argument, 0, 'x')
        //init
    },
    {
        long_optsNew!(b"file\0", required_argument, 0, 'f')
        //init
    },
    {
        long_optsNew!(b"help\0", no_argument, 0, 'h')
        //init
    },
    {
        long_optsNew!(b"quiet\0", no_argument, 0, 'q')
        //init
    },
    {
        long_optsNew!(b"strict\0", no_argument, 0, 's')
        //init
    },
    {
        long_optsNew!(b"version\0", no_argument, 0, 'V')
        //init
    },
    {
        long_optsNew!(0, no_argument, 0, '\0')
        //init
    },
];

#[macro_export]
macro_rules! lineno_editorsNew {
    ($name:expr) => {
        $name as *const u8 as *const libc::c_char as *mut libc::c_char
    };
}

/*
 * List of editors that support the "+lineno" command line syntax.
 * If an entry starts with '*' the tail end of the string is matched.
 * No other wild cards are supported.
 */
static mut lineno_editors: [*mut libc::c_char; 16] = [
    lineno_editorsNew!(b"ex\0"),
    lineno_editorsNew!(b"nex\0"),
    lineno_editorsNew!(b"vi\0"),
    lineno_editorsNew!(b"nvi\0"),
    lineno_editorsNew!(b"vim\0"),
    lineno_editorsNew!(b"elvis\0"),
    lineno_editorsNew!(b"*macs\0"),
    lineno_editorsNew!(b"mg\0"),
    lineno_editorsNew!(b"vile\0"),
    lineno_editorsNew!(b"jove\0"),
    lineno_editorsNew!(b"pico\0"),
    lineno_editorsNew!(b"nano\0"),
    lineno_editorsNew!(b"ee\0"),
    lineno_editorsNew!(b"joe\0"),
    lineno_editorsNew!(b"zile\0"),
    lineno_editorsNew!(0),
];
//unsafe
unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) -> libc::c_int {
    let mut sp: *mut sudoersfile = std::ptr::null_mut::<sudoersfile>();
    let mut editor: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut editor_argv: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut export_path: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut ch: libc::c_int = 0;
    let mut oldlocale: libc::c_int = 0;
    let mut editor_argc: libc::c_int = 0;
    let mut exitcode: libc::c_int = 0 as libc::c_int;
    let mut quiet: bool = false;
    let mut strict: bool = false;
    let mut fflag: bool = false;
    debug_decl!(SUDOERS_DEBUG_MAIN!());

    initprogname(if argc > 0 as libc::c_int {
        *argv.offset(0 as libc::c_int as isize) as *const libc::c_char
    } else {
        b"viutsudo\0" as *const u8 as *const libc::c_char
    });
    if !sudoers_initlocale(
        setlocale(LC_ALL, b"\0" as *const u8 as *const libc::c_char),
        (*sudo_defs_table
            .as_mut_ptr()
            .offset(69 as libc::c_int as isize))
        .sd_un
        .str_0,
    ) {
        sudo_fatalx!(
            b"%s: %s\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            b"unable to allocate memory\0" as *const u8 as *const libc::c_char
        );
    }
    sudo_warn_set_locale_func_v1(Some(
        sudoers_warn_setlocale as unsafe extern "C" fn(bool, *mut libc::c_int) -> bool,
    ));
    bindtextdomain(
        b"sudoers\0" as *const u8 as *const libc::c_char,
        b"/usr/share/locale\0" as *const u8 as *const libc::c_char,
    );
    textdomain(b"sudoers\0" as *const u8 as *const libc::c_char);
    if argc < 1 as libc::c_int {
        usage(1 as libc::c_int);
    }

    /* Register fatal/fatalx callback. */
    sudo_fatal_callback_register_v1(Some(visudo_cleanup as unsafe extern "C" fn() -> ()));

    /* Set sudoers locale callback. */
    let fresh0 = &mut (*sudo_defs_table.as_mut_ptr().offset(I_SUDOERS_LOCALE)).callback;
    *fresh0 = Some(sudoers_locale_callback as unsafe extern "C" fn(*const sudo_defs_val) -> bool);

    /* Read debug and plugin sections of sudo.conf. */
    if sudo_conf_read_v1(
        std::ptr::null::<libc::c_char>(),
        SUDO_CONF_DEBUG | SUDO_CONF_PLUGINS,
    ) == -(1 as libc::c_int)
    {
        exit(EXIT_FAILURE);
    }

    /* Initialize the debug subsystem. */
    if !sudoers_debug_register(
        sudo_getprogname(),
        sudo_conf_debug_files_v1(sudo_getprogname()),
    ) {
        exit(EXIT_FAILURE);
    }

    /* Parse sudoers plugin options, if any. */
    parse_sudoers_options();

    /*
     * Arg handling.
     */
    strict = false;
    quiet = strict;
    fflag = quiet;
    checkonly = fflag;
    loop {
        ch = getopt_long(
            argc,
            argv as *const *mut libc::c_char,
            short_opts.as_ptr(),
            long_opts.as_mut_ptr(),
            std::ptr::null_mut::<libc::c_int>(),
        );
        if ch == -(1 as libc::c_int) {
            // current_block = 17788412896529399552;
            break;
        }
        match ch as u8 as char {
            'V' => {
                printf(
                    b"%s version %s\n\0" as *const u8 as *const libc::c_char,
                    sudo_getprogname(),
                    PACKAGE_VERSION!(),
                );
                printf(
                    b"%s grammar version %d\n\0" as *const u8 as *const libc::c_char,
                    sudo_getprogname(),
                    SUDOERS_GRAMMAR_VERSION,
                );

                sudo_debug_exit_int_v1(
                    get_function_name!(),
                    get_file_name!(),
                    line!() as libc::c_int,
                    sudo_debug_subsys as libc::c_int,
                    exitcode,
                );
                exit(exitcode);
            }
            'c' => {
                checkonly = true;
            }
            'f' => {
                sudoers_file = optarg;
                fflag = true;
            }
            'h' => {
                help();
            }
            's' => {
                strict = true;
            }
            'q' => {
                quiet = true;
            }
            'x' => {
                export_path = optarg;
            }
            _ => {
                usage(1 as libc::c_int);
            }
        }
    }

    argc -= optind;
    argv = argv.offset(optind as isize);

    /* Check for optional sudoers file argument. */
    match argc {
        0 => {}
        1 => {
            if !fflag {
                sudoers_file = *argv;
                fflag = true;
            }
        }
        _ => {
            usage(1 as libc::c_int);
        }
    }

    if !export_path.is_null() {
        /* Backwards compatibility for the time being. */
        sudo_warnx!(
            b"the -x option will be removed in a future release\0" as *const u8
                as *const libc::c_char,
        );
        sudo_warnx!(
            b"please consider using the cvtsudoers utility instead\0" as *const u8
                as *const libc::c_char,
        );
        execlp(
            b"cvtsudoers\0" as *const u8 as *const libc::c_char,
            b"cvtsudoers\0" as *const u8 as *const libc::c_char,
            b"-f\0" as *const u8 as *const libc::c_char,
            b"json\0" as *const u8 as *const libc::c_char,
            b"-o\0" as *const u8 as *const libc::c_char,
            export_path,
            sudoers_file,
            std::ptr::null_mut::<libc::c_char>(),
        );

        sudo_fatal!(
            b"unable to execute %s\0" as *const u8 as *const libc::c_char,
            b"cvtsudoers\0" as *const u8 as *const libc::c_char
        );
    }

    /* Mock up a fake sudo_user struct. */
    sudo_user.cmnd_base = b"\0" as *const u8 as *const libc::c_char as *mut libc::c_char;
    sudo_user.cmnd = sudo_user.cmnd_base;
    if geteuid() == 0 as libc::c_int as libc::c_uint {
        let mut user: *const libc::c_char =
            getenv(b"SUDO_USER\0" as *const u8 as *const libc::c_char);
        if !user.is_null() && *user as libc::c_int != '\0' as i32 {
            sudo_user.pw = sudo_getpwnam(user);
        }
    }
    if (sudo_user.pw).is_null() {
        sudo_user.pw = sudo_getpwuid(getuid());
        if (sudo_user.pw).is_null() {
            sudo_fatalx!(
                b"you do not exist in the %s database\0" as *const u8 as *const libc::c_char,
                b"passwd\0" as *const u8 as *const libc::c_char,
            );
        }
    }
    get_hostname();

    /* Setup defaults data structures. */
    if !init_defaults() {
        sudo_fatalx!(
            b"unable to initialize sudoers default values\0" as *const u8 as *const libc::c_char,
        );
    }
    if checkonly {
        exitcode = if check_syntax(sudoers_file, quiet, strict, fflag) as libc::c_int != 0 {
            0 as libc::c_int
        } else {
            1 as libc::c_int
        };

        sudo_debug_exit_int_v1(
            get_function_name!(),
            get_file_name!(),
            line!() as libc::c_int,
            sudo_debug_subsys as libc::c_int,
            exitcode,
        );
        exit(exitcode);
    }
    /*
     * Parse the existing sudoers file(s) to highlight any existing
     * errors and to pull in editor and env_editor conf values.
     */
    sudoersin = open_sudoers(
        sudoers_file,
        1 as libc::c_int != 0,
        std::ptr::null_mut::<bool>(),
    );
    if sudoersin.is_null() {
        exit(1 as libc::c_int);
    }
    init_parser(sudoers_file, quiet);
    sudoers_setlocale(1 as libc::c_int, &mut oldlocale);
    sudoersparse();
    update_defaults(
        &mut parsed_policy,
        std::ptr::null_mut::<defaults_list>(),
        SETDEF_GENERIC | SETDEF_HOST | SETDEF_USER,
        quiet,
    );
    sudoers_setlocale(oldlocale, std::ptr::null_mut::<libc::c_int>());
    editor = get_editor(&mut editor_argc, &mut editor_argv);

    /* Install signal handlers to clean up temp files if we are killed. */
    setup_signals();

    /* Edit the sudoers file(s) */
    sp = sudoerslist.tqh_first;
    while !sp.is_null() {
        if (*sp).doedit {
            if sp != sudoerslist.tqh_first {
                println!("press return to edit {:#?}: ", (*sp).path);

                loop {
                    ch = getchar();
                    if !(ch != -(1 as libc::c_int) && ch != '\n' as i32) {
                        break;
                    }
                }
            }
            edit_sudoers(sp, editor, editor_argc, editor_argv, -(1 as libc::c_int));
        }
        sp = (*sp).entries.tqe_next;
    }

    /*
     * Check edited files for a parse error, re-edit any that fail
     * and install the edited files as needed.
     */
    if reparse_sudoers(editor, editor_argc, editor_argv, strict, quiet) {
        sp = sudoerslist.tqh_first;
        while !sp.is_null() {
            install_sudoers(sp, fflag);
            sp = (*sp).entries.tqe_next;
        }
    }
    free(editor as *mut libc::c_void);

    sudo_debug_exit_int_v1(
        get_function_name!(),
        get_file_name!(),
        line!() as libc::c_int,
        sudo_debug_subsys as libc::c_int,
        exitcode,
    );
    exit(exitcode);
}
fn get_editor(
    mut editor_argc: *mut libc::c_int,
    mut editor_argv: *mut *mut *mut libc::c_char,
) -> *mut libc::c_char {
    let mut editor_path: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut whitelist: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut env_editor: *const libc::c_char = std::ptr::null::<libc::c_char>();
    static mut files: [*mut libc::c_char; 2] = [
        b"+1\0" as *const u8 as *const libc::c_char as *mut libc::c_char,
        b"sudoers\0" as *const u8 as *const libc::c_char as *mut libc::c_char,
    ];
    let mut whitelist_len: libc::c_uint = 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        /* Build up editor whitelist from def_editor unless env_editor is set. */
        if def_env_editor!() == 0 {
            let mut cp: *const libc::c_char = std::ptr::null::<libc::c_char>();
            let mut ep: *const libc::c_char = std::ptr::null::<libc::c_char>();
            let mut def_editor_end: *const libc::c_char =
                def_editor!().offset(strlen(def_editor!()) as isize);

            /* Count number of entries in whitelist and split into a list. */
            cp = sudo_strsplit_v1(
                def_editor!(),
                def_editor_end,
                b":\0" as *const u8 as *const libc::c_char,
                &mut ep,
            );
            while !cp.is_null() {
                whitelist_len = whitelist_len.wrapping_add(1);
                cp = sudo_strsplit_v1(
                    std::ptr::null::<libc::c_char>(),
                    def_editor_end,
                    b":\0" as *const u8 as *const libc::c_char,
                    &mut ep,
                );
            }

            whitelist = reallocarray(
                std::ptr::null_mut::<libc::c_void>(),
                whitelist_len.wrapping_add(1 as libc::c_int as libc::c_uint) as size_t,
                ::core::mem::size_of::<*mut libc::c_char>() as libc::c_ulong,
            ) as *mut *mut libc::c_char;
            if whitelist.is_null() {
                sudo_fatalx!(
                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                    get_function_name!(),
                    b"unable to allocate memory\0" as *const u8 as *const libc::c_char
                );
            }
            whitelist_len = 0 as libc::c_int as libc::c_uint;
            cp = sudo_strsplit_v1(
                def_editor!(),
                def_editor_end,
                b":\0" as *const u8 as *const libc::c_char,
                &mut ep,
            );

            while !cp.is_null() {
                let fresh1 = &mut *whitelist.offset(whitelist_len as isize);
                *fresh1 = strndup(cp, ep.offset_from(cp) as libc::c_long as size_t);
                if (*whitelist.offset(whitelist_len as isize)).is_null() {
                    sudo_fatalx!(
                        b"%s: %s\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        b"unable to allocate memory\0" as *const u8 as *const libc::c_char
                    );
                }
                whitelist_len = whitelist_len.wrapping_add(1);
                cp = sudo_strsplit_v1(
                    std::ptr::null::<libc::c_char>(),
                    def_editor_end,
                    b":\0" as *const u8 as *const libc::c_char,
                    &mut ep,
                );
            }
            let fresh2 = &mut *whitelist.offset(whitelist_len as isize);
            *fresh2 = std::ptr::null_mut::<libc::c_char>();
        }

        editor_path = find_editor(
            2 as libc::c_int,
            files.as_mut_ptr(),
            editor_argc,
            editor_argv,
            whitelist,
            &mut env_editor,
            true,
        );
        if editor_path.is_null() {
            if def_env_editor!() != 0 && !env_editor.is_null() {
                /* We are honoring $EDITOR so this is a fatal error. */
                sudo_fatalx!(
                    b"specified editor (%s) doesn't exist\0" as *const u8 as *const libc::c_char,
                    env_editor
                );
            }

            sudo_fatalx!(
                b"no editor found (editor path = %s)\0" as *const u8 as *const libc::c_char,
                def_editor!()
            );
        }
        if !whitelist.is_null() {
            loop {
                let fresh3 = whitelist_len;
                whitelist_len = whitelist_len.wrapping_sub(1);
                if fresh3 == 0 {
                    break;
                }
                free(*whitelist.offset(whitelist_len as isize) as *mut libc::c_void);
            }
            free(whitelist as *mut libc::c_void);
        }
        debug_return_str!(editor_path);
    } //unsafe
}

/*
 * Check whether or not the specified editor matched lineno_editors[].
 * Returns true if yes, false if no.
 */
fn editor_supports_plus(mut editor: *const libc::c_char) -> bool {
    unsafe {
        let mut editor_base: *const libc::c_char = strrchr(editor, '/' as i32);
        let mut cp: *const libc::c_char = std::ptr::null::<libc::c_char>();
        let mut av: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        if !editor_base.is_null() {
            editor_base = editor_base.offset(1);
        } else {
            editor_base = editor;
        }
        if *editor_base as libc::c_int == 'r' as i32 {
            editor_base = editor_base.offset(1);
        }
        av = lineno_editors.as_mut_ptr();
        loop {
            cp = *av;
            /* We only handle a leading '*' wildcard. */
            if cp.is_null() {
                break;
            }
            if *cp as libc::c_int == '*' as i32 {
                let mut blen: size_t = strlen(editor_base);
                cp = cp.offset(1);
                let mut clen: size_t = strlen(cp);
                if blen >= clen
                    && strcmp(
                        cp,
                        editor_base.offset(blen as isize).offset(-(clen as isize)),
                    ) == 0 as libc::c_int
                {
                    break;
                }

                /*if blen >= clen {
                    if strcmp(
                        cp,
                        editor_base.offset(blen as isize).offset(-(clen as isize)),
                    ) == 0 as libc::c_int
                    {
                        break;
                    }
                }*/
            } else if strcmp(cp, editor_base) == 0 as libc::c_int {
                break;
            }
            av = av.offset(1);
        }

        debug_return_bool!(!cp.is_null());
    }
}

/*
 * Edit each sudoers file.
 * Returns true on success, else false.
 */
fn edit_sudoers(
    mut sp: *mut sudoersfile,
    mut editor: *mut libc::c_char,
    mut editor_argc: libc::c_int,
    mut editor_argv: *mut *mut libc::c_char,
    mut lineno: libc::c_int,
) -> bool {
    let mut tfd: libc::c_int = 0;
    let mut modified: bool = false;
    let mut ac: libc::c_int = 0;
    let mut linestr: [libc::c_char; 64] = [0; 64];
    let mut ts: timespec = timespec {
        tv_sec: 0,
        tv_nsec: 0,
    };
    let mut times: [timespec; 2] = [timespec {
        tv_sec: 0,
        tv_nsec: 0,
    }; 2];
    let mut orig_mtim: timespec = timespec {
        tv_sec: 0,
        tv_nsec: 0,
    };
    let mut orig_size: off_t = 0;
    let mut sb: stat = sb_all_arch;
    let mut ret: bool = 0 as libc::c_int != 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        if fstat((*sp).fd, &mut sb) == -(1 as libc::c_int) {
            sudo_fatal!(
                b"unable to stat %s\0" as *const u8 as *const libc::c_char,
                (*sp).path
            );
        }
        orig_size = sb.st_size;

        // mtim_get(&sb, orig_mtim);
        orig_mtim.tv_sec = sb.st_mtim.tv_sec;
        orig_mtim.tv_nsec = sb.st_mtim.tv_nsec;

        /* Create the temp file if needed and set timestamp. */
        if ((*sp).tpath).is_null() {
            if asprintf(
                &mut (*sp).tpath as *mut *mut libc::c_char,
                b"%s.tmp\0" as *const u8 as *const libc::c_char,
                (*sp).path,
            ) == -(1 as libc::c_int)
            {
                sudo_fatalx!(
                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                    get_function_name!(),
                    b"unable to allocate memory\0" as *const u8 as *const libc::c_char
                );
            }
            tfd = open((*sp).tpath, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRUSR);
            if tfd < 0 as libc::c_int {
                sudo_fatal!(b"%s\0" as *const u8 as *const libc::c_char, (*sp).tpath);
            }

            /* Copy sp->path -> sp->tpath and reset the mtime. */
            if orig_size != 0 as libc::c_int as libc::c_long {
                let mut buf: [libc::c_char; 4096] = [0; 4096];
                let mut lastch: libc::c_char = '\0' as i32 as libc::c_char;
                let mut nread: ssize_t = 0;
                lseek((*sp).fd, 0 as libc::c_int as off_t, 0 as libc::c_int);
                loop {
                    nread = read(
                        (*sp).fd,
                        buf.as_mut_ptr() as *mut libc::c_void,
                        ::core::mem::size_of::<[libc::c_char; 4096]>() as libc::c_ulong,
                    );
                    if nread <= 0 as libc::c_int as libc::c_long {
                        break;
                    }
                    if write(
                        tfd,
                        buf.as_mut_ptr() as *const libc::c_void,
                        nread as size_t,
                    ) != nread
                    {
                        sudo_fatal!(b"write error\0" as *const u8 as *const libc::c_char,);
                    }
                    lastch = buf[(nread - 1 as libc::c_int as libc::c_long) as usize];
                }

                /* Add missing newline at EOF if needed. */
                if lastch as libc::c_int != '\n' as i32 {
                    lastch = '\n' as i32 as libc::c_char;
                    if write(
                        tfd,
                        &mut lastch as *mut libc::c_char as *const libc::c_void,
                        1 as libc::c_int as size_t,
                    ) != 1 as libc::c_int as libc::c_long
                    {
                        sudo_fatal!(b"write error\0" as *const u8 as *const libc::c_char,);
                    }
                }
            }
            close(tfd);
        }
        times[1 as libc::c_int as usize].tv_sec = orig_mtim.tv_sec;
        times[0 as libc::c_int as usize].tv_sec = times[1 as libc::c_int as usize].tv_sec;
        times[1 as libc::c_int as usize].tv_nsec = orig_mtim.tv_nsec;
        times[0 as libc::c_int as usize].tv_nsec = times[1 as libc::c_int as usize].tv_nsec;
        utimensat(
            AT_FDCWD,
            (*sp).tpath,
            times.as_mut_ptr() as *const timespec,
            0 as libc::c_int,
        );

        /* Disable +lineno if editor doesn't support it. */
        if lineno > 0 as libc::c_int && !editor_supports_plus(editor) {
            lineno = -(1 as libc::c_int);
        }

        /*
         * The last 3 slots in the editor argv are: "-- +1 sudoers"
         * Replace those placeholders with the real values.
         */
        ac = editor_argc - 3 as libc::c_int;
        if lineno > 0 as libc::c_int {
            snprintf(
                linestr.as_mut_ptr(),
                ::core::mem::size_of::<[libc::c_char; 64]>() as libc::c_ulong,
                b"+%d\0" as *const u8 as *const libc::c_char,
                lineno,
            );
            let fresh4 = ac;
            ac += 1;
            let fresh5 = &mut *editor_argv.offset(fresh4 as isize);
            *fresh5 = linestr.as_mut_ptr();
        }
        let fresh6 = ac;
        ac += 1;
        let fresh7 = &mut *editor_argv.offset(fresh6 as isize);
        *fresh7 = b"--\0" as *const u8 as *const libc::c_char as *mut libc::c_char;
        let fresh8 = ac;
        ac += 1;
        let fresh9 = &mut *editor_argv.offset(fresh8 as isize);
        *fresh9 = (*sp).tpath;
        let fresh10 = ac;
        ac += 1;
        let fresh11 = &mut *editor_argv.offset(fresh10 as isize);
        *fresh11 = std::ptr::null_mut::<libc::c_char>();

        /*
         * Do the edit:
         *  We cannot check the editor's exit value against 0 since
         *  XPG4 specifies that vi's exit value is a function of the
         *  number of errors during editing (?!?!).
         */
        if sudo_gettime_real_v1(&mut *times.as_mut_ptr().offset(0 as libc::c_int as isize))
            == -(1 as libc::c_int)
        {
            sudo_warn!(b"unable to read the clock\0" as *const u8 as *const libc::c_char,);
            debug_return_bool!(ret);
        }

        if run_command(editor, editor_argv) != -(1 as libc::c_int) {
            if sudo_gettime_real_v1(&mut *times.as_mut_ptr().offset(1 as libc::c_int as isize))
                == -(1 as libc::c_int)
            {
                sudo_warn!(b"unable to read the clock\0" as *const u8 as *const libc::c_char,);
                debug_return_bool!(ret);
            }

            /*
             * Sanity checks.
             */
            if stat((*sp).tpath, &mut sb) < 0 as libc::c_int {
                sudo_warnx!(
                    b"unable to stat temporary file (%s), %s unchanged\0" as *const u8
                        as *const libc::c_char,
                    (*sp).tpath,
                    (*sp).path
                );
                debug_return_bool!(ret);
            }

            if sb.st_size == 0 as libc::c_int as libc::c_long
                && orig_size != 0 as libc::c_int as libc::c_long
            {
                /* Avoid accidental zeroing of main sudoers file. */
                if sp == sudoerslist.tqh_first {
                    sudo_warnx!(
                        b"zero length temporary file (%s), %s unchanged\0" as *const u8
                            as *const libc::c_char,
                        (*sp).tpath,
                        (*sp).path
                    );

                    debug_return_bool!(ret);
                }
            }
        } else {
            sudo_warnx!(
                b"editor (%s) failed, %s unchanged\0" as *const u8 as *const libc::c_char,
                editor,
                (*sp).path
            );
            debug_return_bool!(ret);
        }

        /* Set modified bit if the user changed the file. */
        modified = true;
        // mtim_get(&sb, ts);
        ts.tv_sec = sb.st_mtim.tv_sec;
        ts.tv_nsec = sb.st_mtim.tv_nsec;

        if orig_size == sb.st_size
            && (if orig_mtim.tv_sec == ts.tv_sec {
                (orig_mtim.tv_nsec == ts.tv_nsec) as libc::c_int
            } else {
                (orig_mtim.tv_sec == ts.tv_sec) as libc::c_int
            }) != 0
        {
            /*
             * If mtime and size match but the user spent no measurable
             * time in the editor we can't tell if the file was changed.
             */

            if if times[0 as libc::c_int as usize].tv_sec == times[1 as libc::c_int as usize].tv_sec
            {
                (times[0 as libc::c_int as usize].tv_nsec
                    != times[1 as libc::c_int as usize].tv_nsec) as libc::c_int
            } else {
                (times[0 as libc::c_int as usize].tv_sec != times[1 as libc::c_int as usize].tv_sec)
                    as libc::c_int
            } != 0
            {
                modified = false;
            }
        }

        /*
         * If modified in this edit session, mark as modified.
         */
        if modified {
            (*sp).modified = modified;
        } else {
            sudo_warnx!(
                b"%s unchanged\0" as *const u8 as *const libc::c_char,
                (*sp).tpath,
            );
        }
        ret = true;

        debug_return_bool!(ret);
    }
}

/*
 * Check Defaults and Alias entries.
 * Sets parse_error on error and errorfile/errorlineno if possible.
 */
fn check_defaults_and_aliases(mut strict: bool, mut quiet: bool) {
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        if !check_defaults(&mut parsed_policy, quiet) {
            let mut d: *mut defaults_struct = std::ptr::null_mut::<defaults_struct>();
            rcstr_delref(errorfile);
            errorfile = std::ptr::null_mut::<libc::c_char>();
            errorlineno = -(1 as libc::c_int);
            d = parsed_policy.defaults.tqh_first;
            while !d.is_null() {
                if (*d).error != 0 {
                    /* Defaults parse error, set errorfile/errorlineno. */
                    errorfile = rcstr_addref((*d).file);
                    errorlineno = (*d).lineno;
                    break;
                } else {
                    d = (*d).entries.tqe_next;
                }
            }
            parse_error = true;
        } else if check_aliases(strict, quiet) != 0 as libc::c_int {
            rcstr_delref(errorfile);
            errorfile = std::ptr::null_mut::<libc::c_char>(); /* don't know which file */
            errorlineno = -(1 as libc::c_int);
            parse_error = true;
        }

        debug_return!();
    } //unsafe
}

/*
 * Parse sudoers after editing and re-edit any ones that caused a parse error.
 */
fn reparse_sudoers(
    mut editor: *mut libc::c_char,
    mut editor_argc: libc::c_int,
    mut editor_argv: *mut *mut libc::c_char,
    mut strict: bool,
    mut quiet: bool,
) -> bool {
    let mut sp: *mut sudoersfile = std::ptr::null_mut::<sudoersfile>();
    let mut last: *mut sudoersfile = std::ptr::null_mut::<sudoersfile>();
    let mut fp: *mut FILE = std::ptr::null_mut::<FILE>();
    let mut ch: libc::c_int = 0;
    let mut oldlocale: libc::c_int = 0;

    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        /*
         * Parse the edited sudoers files and do sanity checking
         */
        loop {
            sp = sudoerslist.tqh_first;
            if sp.is_null() {
                break;
            }
            last = *(*(sudoerslist.tqh_last as *mut sudoersfile_list)).tqh_last;
            fp = fopen((*sp).tpath, b"r+\0" as *const u8 as *const libc::c_char);
            if fp.is_null() {
                sudo_fatalx!(
                    b"unable to re-open temporary file (%s), %s unchanged.\0" as *const u8
                        as *const libc::c_char,
                    (*sp).tpath,
                    (*sp).path
                );
            }

            /* Clean slate for each parse */
            if !init_defaults() {
                sudo_fatalx!(
                    b"unable to initialize sudoers default values\0" as *const u8
                        as *const libc::c_char,
                );
            }
            init_parser((*sp).path, quiet);

            /* Parse the sudoers temp file(s) */
            sudoersrestart(fp);
            sudoers_setlocale(1 as libc::c_int, &mut oldlocale);
            if sudoersparse() != 0 && !parse_error {
                sudo_warnx!(
                    b"unabled to parse temporary file (%s), unknown error\0" as *const u8
                        as *const libc::c_char,
                    (*sp).tpath
                );

                parse_error = true;
                rcstr_delref(errorfile);
                errorfile = rcstr_dup((*sp).path);
                if errorfile.is_null() {
                    sudo_fatalx!(
                        b"%s: %s\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        b"unable to allocate memory\0" as *const u8 as *const libc::c_char
                    );
                }
            }
            fclose(sudoersin);
            if !parse_error {
                update_defaults(
                    &mut parsed_policy,
                    std::ptr::null_mut::<defaults_list>(),
                    SETDEF_GENERIC | SETDEF_HOST | SETDEF_USER,
                    true,
                );
                check_defaults_and_aliases(strict, quiet);
            }
            sudoers_setlocale(oldlocale, std::ptr::null_mut::<libc::c_int>());

            /*
             * Got an error, prompt the user for what to do now.
             */
            if parse_error {
                match whatnow() as u8 as char {
                    'Q' => {
                        parse_error = false;
                    }
                    'x' => {
                        visudo_cleanup();
                        debug_return_bool!(false);
                    }
                    _ => {
                        /* Edit file with the parse error */
                        sp = sudoerslist.tqh_first;
                        while !sp.is_null() {
                            if errorfile.is_null()
                                || strcmp((*sp).path, errorfile) == 0 as libc::c_int
                            {
                                edit_sudoers(sp, editor, editor_argc, editor_argv, errorlineno);
                                if !errorfile.is_null() {
                                    break;
                                }
                            }
                            sp = (*sp).entries.tqe_next;
                        }
                        if !errorfile.is_null() && sp.is_null() {
                            sudo_fatalx!(
                                b"internal error, unable to find %s in list!\0" as *const u8
                                    as *const libc::c_char,
                                sudoers
                            );
                        }
                    }
                }
            }

            /* If any new #include directives were added, edit them too. */
            sp = (*last).entries.tqe_next;
            if !sp.is_null() {
                let mut modified: bool = 0 as libc::c_int != 0;
                loop {
                    println!("press return to edit {:#?}: ", (*sp).path);
                    loop {
                        ch = getchar();
                        if !(ch != -(1 as libc::c_int) && ch != '\n' as i32) {
                            break;
                        }
                    }
                    edit_sudoers(sp, editor, editor_argc, editor_argv, -(1 as libc::c_int));
                    if (*sp).modified {
                        modified = 1 as libc::c_int != 0;
                    }
                    sp = (*sp).entries.tqe_next;
                    if sp.is_null() {
                        break;
                    }
                }
                /* Reparse sudoers if newly added includes were modified. */
                if modified {
                    continue;
                }
            }
            /* If all sudoers files parsed OK we are done. */
            if !parse_error {
                break;
            }
        }

        debug_return_bool!(true);
    }
}

/*
 * Set the owner and mode on a sudoers temp file and
 * move it into place.  Returns true on success, else false.
 */
fn install_sudoers(mut sp: *mut sudoersfile, mut oldperms: bool) -> bool {
    let mut sb: stat = sb_all_arch;
    let mut ret: bool = 0 as libc::c_int != 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        if ((*sp).tpath).is_null() {
            debug_return_bool!(ret);
        }

        if !(*sp).modified {
            /*
             * No changes but fix owner/mode if needed.
             */

            unlink((*sp).tpath);
            if !oldperms && fstat((*sp).fd, &mut sb) != -1 {
                if (sb.st_uid != sudoers_uid || sb.st_gid != sudoers_gid)
                    && chown((*sp).path, sudoers_uid, sudoers_gid) != 0 as libc::c_int
                {
                    sudo_debug_printf!(
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_ERRNO,
                        b"%s: unable to chown %d:%d %s\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        sudoers_uid as libc::c_int,
                        sudoers_gid as libc::c_int,
                        (*sp).path
                    );
                } //  sb.st_uid

                /*if sb.st_uid != sudoers_uid || sb.st_gid != sudoers_gid {
                    if chown((*sp).path, sudoers_uid, sudoers_gid) != 0 as libc::c_int {
                        sudo_debug_printf!(
                            SUDO_DEBUG_ERROR | SUDO_DEBUG_ERRNO,
                            b"%s: unable to chown %d:%d %s\0" as *const u8 as *const libc::c_char,
                            get_function_name!(),
                            sudoers_uid as libc::c_int,
                            sudoers_gid as libc::c_int,
                            (*sp).path
                        );
                    } // chown
                }*/
                //  sb.st_uid

                if sb.st_mode & ACCESSPERMS!() as libc::c_uint != sudoers_mode
                    && chmod((*sp).path, sudoers_mode) != 0
                {
                    sudo_debug_printf!(
                        SUDO_DEBUG_ERROR | SUDO_DEBUG_ERRNO,
                        b"%s: unable to chmod 0%o %s\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        sudoers_mode as libc::c_int,
                        (*sp).path
                    );
                }

                /*if sb.st_mode & ACCESSPERMS!() as libc::c_uint != sudoers_mode {
                    if chmod((*sp).path, sudoers_mode) != 0 {
                        sudo_debug_printf!(
                            SUDO_DEBUG_ERROR | SUDO_DEBUG_ERRNO,
                            b"%s: unable to chmod 0%o %s\0" as *const u8 as *const libc::c_char,
                            get_function_name!(),
                            sudoers_mode as libc::c_int,
                            (*sp).path
                        );
                    }
                }*/
            } // oldperms
            ret = true;
            debug_return_bool!(ret);
        }

        /*
         * Change mode and ownership of temp file so when
         * we move it to sp->path things are kosher.
         */
        if oldperms {
            /* Use perms of the existing file.  */
            if fstat((*sp).fd, &mut sb) == -(1 as libc::c_int) {
                sudo_fatal!(
                    b"unable to stat %s\0" as *const u8 as *const libc::c_char,
                    (*sp).path
                );
            }
            if chown((*sp).tpath, sb.st_uid, sb.st_gid) != 0 as libc::c_int {
                sudo_warn!(
                    b"unable to set (uid, gid) of %s to (%u, %u)\0" as *const u8
                        as *const libc::c_char,
                    (*sp).tpath,
                    sb.st_uid,
                    sb.st_gid
                );
            }
            if chmod((*sp).tpath, sb.st_mode & ACCESSPERMS!() as libc::c_uint) != 0 {
                sudo_warn!(
                    b"unable to change mode of %s to 0%o\0" as *const u8 as *const libc::c_char,
                    (*sp).tpath,
                    sb.st_mode & ACCESSPERMS!() as libc::c_uint
                );
            }
        } else {
            if chown((*sp).tpath, sudoers_uid, sudoers_gid) != 0 {
                sudo_warn!(
                    b"unable to set (uid, gid) of %s to (%u, %u)\0" as *const u8
                        as *const libc::c_char,
                    (*sp).tpath,
                    sudoers_uid,
                    sudoers_gid
                );
                debug_return_bool!(ret);
            }
            if chmod((*sp).tpath, sudoers_mode) != 0 {
                sudo_warn!(
                    b"unable to change mode of %s to 0%o\0" as *const u8 as *const libc::c_char,
                    (*sp).tpath,
                    sudoers_mode
                );
                debug_return_bool!(ret);
            }
        }

        /*
         * Now that sp->tpath is sane (parses ok) it needs to be
         * rename(2)'d to sp->path.  If the rename(2) fails we try using
         * mv(1) in case sp->tpath and sp->path are on different file systems.
         */
        if rename((*sp).tpath, (*sp).path) == 0 as libc::c_int {
            free((*sp).tpath as *mut libc::c_void);
            (*sp).tpath = std::ptr::null_mut::<libc::c_char>();
        } else if *__errno_location() == EXDEV {
            let mut av: [*mut libc::c_char; 4] = [std::ptr::null_mut::<libc::c_char>(); 4];
            sudo_warnx!(
                b"%s and %s not on the same file system, using mv to rename\0" as *const u8
                    as *const libc::c_char,
                (*sp).tpath,
                (*sp).path,
            );

            /* Build up argument vector for the command */
            av[0_usize] = strrchr(_PATH_MV!(), '/' as i32);
            if !(av[0_usize]).is_null() {
                av[0_usize] = (av[0_usize]).offset(1);
            } else {
                av[0_usize] = _PATH_MV!() as *mut libc::c_char;
            }
            av[1_usize] = (*sp).tpath;
            av[2_usize] = (*sp).path;
            av[3_usize] = std::ptr::null_mut::<libc::c_char>();

            /* And run it... */
            if run_command(_PATH_MV!() as *mut libc::c_char, av.as_mut_ptr()) != 0 {
                sudo_warnx!(
                    b"command failed: '%s %s %s', %s unchanged\0" as *const u8
                        as *const libc::c_char,
                    _PATH_MV!(),
                    (*sp).tpath,
                    (*sp).path,
                    (*sp).path
                );
                unlink((*sp).tpath);
                free((*sp).tpath as *mut libc::c_void);
                (*sp).tpath = std::ptr::null_mut::<libc::c_char>();
                debug_return_bool!(ret);
            }

            free((*sp).tpath as *mut libc::c_void);
            (*sp).tpath = std::ptr::null_mut::<libc::c_char>();
        } else {
            sudo_warn!(
                b"error renaming %s, %s unchanged\0" as *const u8 as *const libc::c_char,
                (*sp).tpath,
                (*sp).path
            );
            unlink((*sp).tpath);
            debug_return_bool!(ret);
        }
        /*} else {
            if *__errno_location() == EXDEV {
                let mut av: [*mut libc::c_char; 4] = [std::ptr::null_mut::<libc::c_char>(); 4];
                sudo_warnx!(
                    b"%s and %s not on the same file system, using mv to rename\0" as *const u8
                        as *const libc::c_char,
                    (*sp).tpath,
                    (*sp).path,
                );

                /* Build up argument vector for the command */
                av[0_usize] = strrchr(_PATH_MV!(), '/' as i32);
                if !(av[0_usize]).is_null() {
                    av[0_usize] = (av[0_usize]).offset(1);
                } else {
                    av[0_usize] = _PATH_MV!() as *mut libc::c_char;
                }
                av[1_usize] = (*sp).tpath;
                av[2_usize] = (*sp).path;
                av[3_usize] = std::ptr::null_mut::<libc::c_char>();

                /* And run it... */
                if run_command(_PATH_MV!() as *mut libc::c_char, av.as_mut_ptr()) != 0 {
                    sudo_warnx!(
                        b"command failed: '%s %s %s', %s unchanged\0" as *const u8
                            as *const libc::c_char,
                        _PATH_MV!(),
                        (*sp).tpath,
                        (*sp).path,
                        (*sp).path
                    );
                    unlink((*sp).tpath);
                    free((*sp).tpath as *mut libc::c_void);
                    (*sp).tpath = std::ptr::null_mut::<libc::c_char>();
                    debug_return_bool!(ret);
                }

                free((*sp).tpath as *mut libc::c_void);
                (*sp).tpath = std::ptr::null_mut::<libc::c_char>();
            } else {
                sudo_warn!(
                    b"error renaming %s, %s unchanged\0" as *const u8 as *const libc::c_char,
                    (*sp).tpath,
                    (*sp).path
                );
                unlink((*sp).tpath);
                debug_return_bool!(ret);
            }
        }*/
        ret = true;

        debug_return_bool!(ret);
    }
}

/*
 * Assuming a parse error occurred, prompt the user for what they want
 * to do now.  Returns the first letter of their choice.
 */
fn whatnow() -> libc::c_int {
    let mut choice: libc::c_int = 0;
    let mut c: libc::c_int = 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        loop {
            fputs(b"What now? \0" as *const u8 as *const libc::c_char, stdout);
            choice = getchar();
            c = choice;
            while c != '\n' as i32 && c != -(1 as libc::c_int) {
                c = getchar();
            }

            match choice {
                -1 | 101 | 120 | 81 => {
                    if choice == -1 {
                        choice = 'x' as i32;
                    }
                    debug_return_int!(choice);
                }
                _ => {
                    puts(
                        b"Options are:\n  
                          (e)dit sudoers file again\n  
                          e(x)it without saving changes to sudoers file\n  
                          (Q)uit and save changes to sudoers file (DANGER!)\n\0"
                            as *const u8 as *const libc::c_char,
                    );
                }
            }
        }
    }
}

/*
 * Install signal handlers for visudo.
 */
fn setup_signals() {
    let mut sa: sigaction = sigaction {
        __sigaction_handler: Signal_handler { sa_handler: None },
        sa_mask: __sigset_t { __val: [0; 16] },
        sa_flags: 0,
        sa_restorer: None,
    };
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());
    }

    /*
     * Setup signal handlers to cleanup nicely.
     */
    unsafe {
        memset(
            &mut sa as *mut sigaction as *mut libc::c_void,
            0 as libc::c_int,
            ::core::mem::size_of::<sigaction>() as libc::c_ulong,
        )
    };
    unsafe { sigemptyset(&mut sa.sa_mask) };
    sa.sa_flags = SA_RESTART;
    sa.__sigaction_handler.sa_handler = Some(quit as unsafe extern "C" fn(libc::c_int) -> ());
    unsafe { sigaction(SIGTERM, &sa, std::ptr::null_mut::<sigaction>()) };
    unsafe { sigaction(SIGHUP, &sa, std::ptr::null_mut::<sigaction>()) };
    unsafe { sigaction(SIGINT, &sa, std::ptr::null_mut::<sigaction>()) };
    unsafe { sigaction(SIGQUIT, &sa, std::ptr::null_mut::<sigaction>()) };

    unsafe {
        debug_return!();
    }
}
fn run_command(mut path: *mut libc::c_char, mut argv: *mut *mut libc::c_char) -> libc::c_int {
    let mut status: libc::c_int = 0;
    let mut pid: pid_t = 0;
    let mut rv: pid_t = 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());
    }

    pid = unsafe { sudo_debug_fork_v1() };
    match pid {
        -1 => unsafe {
            sudo_fatal!(
                b"unable to execute %s\0" as *const u8 as *const libc::c_char,
                path
            );
        },
        0 => {
            unsafe { sudo_closefrom(2 as libc::c_int + 1 as libc::c_int) };
            unsafe { execv(path, argv as *const *mut libc::c_char) };
            unsafe {
                sudo_warn!(
                    b"unable to run %s\0" as *const u8 as *const libc::c_char,
                    path,
                );
            }
            unsafe { _exit(127 as libc::c_int) };
        }
        _ => {}
    }
    loop {
        rv = unsafe { waitpid(pid, &mut status, 0 as libc::c_int) };
        if rv == -(1 as libc::c_int) && unsafe { *__errno_location() } != EINTR {
            break;
        }
        if rv != -1 && !WIFSTOPPED!(status) {
            break;
        }
    }
    if rv != -(1 as libc::c_int) {
        rv = if WIFEXITED!(status) {
            WEXITSTATUS!(status)
        } else {
            -(1 as libc::c_int)
        };
    }

    unsafe {
        debug_return_int!(rv);
    }
}
fn check_owner(mut path: *const libc::c_char, mut quiet: bool) -> bool {
    let mut sb: stat = sb_all_arch;
    let mut ok: bool = true;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());
    

    if stat(path, &mut sb) == 0 as libc::c_int {
        if sb.st_uid != unsafe { sudoers_uid } || sb.st_gid != unsafe { sudoers_gid } {
            ok = false;
            if !quiet {
                unsafe {
                    fprintf(
                        stderr,
                        b"%s: wrong owner (uid, gid) should be (%u, %u)\n\0" as *const u8
                            as *const libc::c_char,
                        path,
                        sudoers_uid,
                        sudoers_gid,
                    )
                };
            }
        }
        if (sb.st_mode & ALLPERMS!() as libc::c_uint) != unsafe { sudoers_mode } {
            ok = false;
            if !quiet {
                unsafe {
                    fprintf(
                        stderr,
                        b"%s: bad permissions, should be mode 0%o\n\0" as *const u8
                            as *const libc::c_char,
                        path,
                        sudoers_mode,
                    )
                };
            }
        }
    }
    
        debug_return_bool!(ok);
    }
}
fn check_syntax(
    mut sudoers_file_0: *const libc::c_char,
    mut quiet: bool,
    mut strict: bool,
    mut oldperms: bool,
) -> bool {
    let mut current_block: u64;
    let mut ok: bool = 0 as libc::c_int != 0;
    let mut oldlocale: libc::c_int = 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());
    }

    if unsafe { strcmp(sudoers_file_0, b"-\0" as *const u8 as *const libc::c_char) }
        == 0 as libc::c_int
    {
        unsafe { sudoersin = stdin };
        sudoers_file_0 = b"stdin\0" as *const u8 as *const libc::c_char;
    } else {
        unsafe { sudoersin = fopen(sudoers_file_0, b"r\0" as *const u8 as *const libc::c_char) };
        if unsafe { sudoersin.is_null() } {
            if !quiet {
                unsafe {
                    sudo_warn!(
                        b"unable to open %s\0" as *const u8 as *const libc::c_char,
                        sudoers_file_0
                    );
                }
            }
            unsafe {
                debug_return_bool!(ok);
            }
        }
    }

    if !unsafe { init_defaults() } {
        unsafe {
            sudo_fatalx!(
                b"unable to initialize sudoers default values\0" as *const u8
                    as *const libc::c_char,
            );
        }
    }
    unsafe { init_parser(sudoers_file_0, quiet) };
    unsafe { sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &mut oldlocale) };
    if unsafe { sudoersparse() } != 0 && !unsafe { parse_error } {
        if !quiet {
            unsafe {
                sudo_warnx!(
                    b"failed to parse %s file, unknown error\0" as *const u8 as *const libc::c_char,
                    sudoers_file_0
                );
            }
        }
        unsafe { parse_error = true };
        unsafe { rcstr_delref(errorfile) };
        unsafe { errorfile = rcstr_dup(sudoers_file_0) };
        if unsafe { errorfile.is_null() } {
            unsafe {
                sudo_fatalx!(
                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                    get_function_name!(),
                    b"unable to allocate memory\0" as *const u8 as *const libc::c_char
                );
            }
        }
    }
    if !unsafe { parse_error } {
        unsafe {
            update_defaults(
                &mut parsed_policy,
                std::ptr::null_mut::<defaults_list>(),
                SETDEF_GENERIC | SETDEF_HOST | SETDEF_USER,
                true,
            )
        };
        check_defaults_and_aliases(strict, quiet);
    }
    unsafe { sudoers_setlocale(oldlocale, std::ptr::null_mut::<libc::c_int>()) };
    ok = !unsafe { parse_error };
    unsafe {
        if parse_error {
            if !quiet {
                if errorlineno != -(1 as libc::c_int) {
                    println!(
                        "parse error in {:#?} near line {}\n",
                        errorfile, errorlineno,
                    );
                } else if !errorfile.is_null() {
                    println!("parse error in {:#?}\n", errorfile)
                }
            }
        } else {
            let mut sp: *mut sudoersfile = std::ptr::null_mut::<sudoersfile>();

            /* Parsed OK, check mode and owner. */
            if oldperms as libc::c_int != 0
                || check_owner(sudoers_file_0, quiet) as libc::c_int != 0
            {
                if !quiet {
                    println!(
                        "{}: parsed OK",
                        CStr::from_ptr(sudoers_file).to_str().unwrap()
                    );
                }
            } else {
                ok = false;
            }
            sp = sudoerslist.tqh_first;
            while !sp.is_null() {
                if oldperms as libc::c_int != 0
                    || check_owner((*sp).path, quiet) as libc::c_int != 0
                {
                    if !quiet {
                        println!(
                            "{}: parsed OK",
                            CStr::from_ptr((*sp).path).to_str().unwrap()
                        );
                    }
                } else {
                    ok = false;
                }
                sp = (*sp).entries.tqe_next;
            }
        }
    }

    unsafe {
        debug_return_bool!(ok);
    }
}

fn lock_sudoers(mut entry: *mut sudoersfile) -> bool {
    let mut ch: libc::c_int = 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());
    }

    if !unsafe { sudo_lock_file_v1((*entry).fd, SUDO_TLOCK) } {
        if unsafe { *__errno_location() } == EAGAIN || unsafe { *__errno_location() } == EWOULDBLOCK
        {
            unsafe {
                sudo_warnx!(
                    b"%s busy, try again later\0" as *const u8 as *const libc::c_char,
                    (*entry).path
                );
                debug_return_bool!(false);
            }
        }
        unsafe {
            sudo_warn!(
                b"unable to lock %s\0" as *const u8 as *const libc::c_char,
                (*entry).path
            );
        }

        unsafe {
            fputs(
                b"Edit anyway? [y/N]\0" as *const u8 as *const libc::c_char,
                stdout,
            )
        };
        ch = getchar();
        if ({
            let mut __res: libc::c_int = 0;
            if ::core::mem::size_of::<libc::c_int>() as libc::c_ulong
                > 1 as libc::c_int as libc::c_ulong
            {
                if 0 != 0 {
                    let mut __c: libc::c_int = ch;
                    __res = if __c < -(128 as libc::c_int) || __c > 255 as libc::c_int {
                        __c
                    } else {
                        unsafe { *(*__ctype_tolower_loc()).offset(__c as isize) }
                    };
                } else {
                    __res = tolower(ch);
                }
            } else {
                __res = unsafe { *(*__ctype_tolower_loc()).offset(ch as isize) };
            }
            __res
        }) != 'y' as i32
        {
            unsafe {
                debug_return_bool!(false);
            }
        }
    }
    unsafe {
        debug_return_bool!(true);
    }
}

/*
 * Used to open (and lock) the initial sudoers file and to also open
 * any subsequent files #included via a callback from the parser.
 */
#[no_mangle]
fn open_sudoers(
    mut path: *const libc::c_char,
    mut doedit: bool,
    mut keepopen: *mut bool,
) -> *mut FILE {
    let mut entry: *mut sudoersfile = std::ptr::null_mut::<sudoersfile>();
    let mut fp: *mut FILE = std::ptr::null_mut::<FILE>();
    let mut open_flags: libc::c_int = 0;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());
    }

    if unsafe { checkonly } {
        open_flags = O_RDONLY;
    } else {
        open_flags = O_RDWR | O_CREAT;
    }
    unsafe {
        /* Check for existing entry */
        entry = sudoerslist.tqh_first;
        while !entry.is_null() {
            if strcmp(path, (*entry).path) == 0 as libc::c_int {
                break;
            }
            entry = (*entry).entries.tqe_next;
        }
        if entry.is_null() {
            entry = calloc(
                1 as libc::c_int as libc::c_ulong,
                ::core::mem::size_of::<sudoersfile>() as libc::c_ulong,
            ) as *mut sudoersfile;
            if entry.is_null() || {
                (*entry).path = strdup(path);
                ((*entry).path).is_null()
            } {
                sudo_fatalx!(
                    b"%s: %s\0" as *const u8 as *const libc::c_char,
                    get_function_name!(),
                    b"unable to allocate memory\0" as *const u8 as *const libc::c_char
                );
            }

            (*entry).doedit = doedit;
            (*entry).fd = open((*entry).path, open_flags, sudoers_mode);
            if (*entry).fd == -(1 as libc::c_int) {
                sudo_warn!(b"%s\0" as *const u8 as *const libc::c_char, (*entry).path);
                free(entry as *mut libc::c_void);
                debug_return_ptr!(std::ptr::null_mut::<FILE>());
            }
            if !checkonly && !lock_sudoers(entry) {
                debug_return_ptr!(std::ptr::null_mut::<FILE>());
            }
            fp = fdopen((*entry).fd, b"r\0" as *const u8 as *const libc::c_char);
            if fp.is_null() {
                sudo_fatal!(b"%s\0" as *const u8 as *const libc::c_char, (*entry).path);
            }
            (*entry).entries.tqe_next = std::ptr::null_mut::<sudoersfile>();
            (*entry).entries.tqe_prev = sudoerslist.tqh_last;
            *sudoerslist.tqh_last = entry;
            sudoerslist.tqh_last = &mut (*entry).entries.tqe_next;
        } else if !((*entry).tpath).is_null() {
            /* Already exists, open .tmp version if there is one. */
            fp = fopen((*entry).tpath, b"r\0" as *const u8 as *const libc::c_char);
            if fp.is_null() {
                sudo_fatal!(b"%s\0" as *const u8 as *const libc::c_char, (*entry).tpath);
            }
        } else {
            fp = fdopen((*entry).fd, b"r\0" as *const u8 as *const libc::c_char);
            if fp.is_null() {
                sudo_fatal!(b"%s\0" as *const u8 as *const libc::c_char, (*entry).path);
            }
            rewind(fp);
        }
        if !keepopen.is_null() {
            *keepopen = true;
        }
    }
    unsafe {
        debug_return_ptr!(fp);
    }
}

fn check_alias(
    mut name: *mut libc::c_char,
    mut type_0: libc::c_int,
    mut file: *mut libc::c_char,
    mut lineno: libc::c_int,
    mut strict: bool,
    mut quiet: bool,
) -> libc::c_int {
    let mut m: *mut member = std::ptr::null_mut::<member>();
    let mut a: *mut alias_struct = std::ptr::null_mut::<alias_struct>();
    let mut errors: libc::c_int = 0 as libc::c_int;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_ALIAS!());
    }
    unsafe {
        a = alias_get(&mut parsed_policy, name, type_0);
        if !a.is_null() {
            /* check alias contents */
            m = (*a).members.tqh_first;
            while !m.is_null() {
                if (*m).type0 as libc::c_int == ALIAS {
                    errors += check_alias((*m).name, type_0, (*a).file, (*a).lineno, strict, quiet);
                }
                m = (*m).entries.tqe_next;
            }
            alias_put(a);
        } else {
            if !quiet {
                if *__errno_location() == ELOOP {
                    fprintf(
                        stderr,
                        if strict as libc::c_int != 0 {
                            b"Error: %s:%d cycle in %s \"%s\"\0" as *const u8 as *const libc::c_char
                        } else {
                            b"Warning: %s:%d cycle in %s \"%s\"\0" as *const u8
                                as *const libc::c_char
                        },
                        file,
                        lineno,
                        alias_type_to_string(type_0),
                        name,
                    );
                } else {
                    fprintf(
                        stderr,
                        if strict as libc::c_int != 0 {
                            b"Error: %s:%d %s \"%s\" referenced but not defined\0" as *const u8
                                as *const libc::c_char
                        } else {
                            b"Warning: %s:%d %s \"%s\" referenced but not defined\0" as *const u8
                                as *const libc::c_char
                        },
                        file,
                        lineno,
                        alias_type_to_string(type_0),
                        name,
                    );
                }
                fputc('\n' as i32, stderr);
                if strict as libc::c_int != 0 && errorfile.is_null() {
                    errorfile = rcstr_addref(file);
                    errorlineno = lineno;
                }
            }
            errors += 1;
        }
    }
    unsafe {
        debug_return_int!(errors);
    }
}

/*
 * Iterate through the sudoers datastructures looking for undefined
 * aliases or unused aliases.
 */
fn check_aliases(mut strict: bool, mut quiet: bool) -> libc::c_int {
    let mut used_aliases: *mut rbtree = std::ptr::null_mut::<rbtree>();
    let mut cs: *mut cmndspec = std::ptr::null_mut::<cmndspec>();
    let mut m: *mut member = std::ptr::null_mut::<member>();
    let mut priv_0: *mut privilege = std::ptr::null_mut::<privilege>();
    let mut us: *mut userspec = std::ptr::null_mut::<userspec>();
    let mut errors: libc::c_int = 0 as libc::c_int;
    unsafe {
        debug_decl!(SUDOERS_DEBUG_ALIAS!());
    }
    unsafe {
        used_aliases = alloc_aliases();
        if used_aliases.is_null() {
            sudo_warnx!(
                b"%s: %s\0" as *const u8 as *const libc::c_char,
                get_function_name!(),
                b"unable to allocate memory\0" as *const u8 as *const libc::c_char
            );
            debug_return_int!(-1);
        }

        /* Forward check. */
        us = parsed_policy.userspecs.tqh_first;
        while !us.is_null() {
            m = (*us).users.tqh_first;
            while !m.is_null() {
                if (*m).type0 as libc::c_int == ALIAS {
                    errors += check_alias(
                        (*m).name,
                        USERALIAS,
                        (*us).file,
                        (*us).lineno,
                        strict,
                        quiet,
                    );
                }
                m = (*m).entries.tqe_next;
            }
            priv_0 = (*us).privileges.tqh_first;
            while !priv_0.is_null() {
                m = (*priv_0).hostlist.tqh_first;
                while !m.is_null() {
                    if (*m).type0 as libc::c_int == ALIAS {
                        errors += check_alias(
                            (*m).name,
                            HOSTALIAS,
                            (*us).file,
                            (*us).lineno,
                            strict,
                            quiet,
                        );
                    }
                    m = (*m).entries.tqe_next;
                }
                cs = (*priv_0).cmndlist.tqh_first;
                while !cs.is_null() {
                    if !((*cs).runasuserlist).is_null() {
                        m = (*(*cs).runasuserlist).tqh_first;
                        while !m.is_null() {
                            if (*m).type0 as libc::c_int == ALIAS {
                                errors += check_alias(
                                    (*m).name,
                                    RUNASALIAS,
                                    (*us).file,
                                    (*us).lineno,
                                    strict,
                                    quiet,
                                );
                            }
                            m = (*m).entries.tqe_next;
                        }
                    }
                    if !((*cs).runasgrouplist).is_null() {
                        m = (*(*cs).runasgrouplist).tqh_first;
                        while !m.is_null() {
                            if (*m).type0 as libc::c_int == ALIAS {
                                errors += check_alias(
                                    (*m).name,
                                    RUNASALIAS,
                                    (*us).file,
                                    (*us).lineno,
                                    strict,
                                    quiet,
                                );
                            }
                            m = (*m).entries.tqe_next;
                        }
                    }
                    m = (*cs).cmnd;
                    if (*m).type0 as libc::c_int == ALIAS {
                        errors += check_alias(
                            (*m).name,
                            CMNDALIAS,
                            (*us).file,
                            (*us).lineno,
                            strict,
                            quiet,
                        );
                    }
                    cs = (*cs).entries.tqe_next;
                }
                priv_0 = (*priv_0).entries.tqe_next;
            }
            us = (*us).entries.tqe_next;
        }

        /* Reverse check (destructive) */
        if !alias_find_used(&mut parsed_policy, used_aliases) {
            errors += 1;
        }
        free_aliases(used_aliases);

        /* If all aliases were referenced we will have an empty tree. */
        if !no_aliases(&mut parsed_policy) && !quiet {
            alias_apply(
                &mut parsed_policy,
                Some(
                    print_unused
                        as unsafe extern "C" fn(
                            *mut sudoers_parse_tree,
                            *mut alias_struct,
                            *mut libc::c_void,
                        ) -> libc::c_int,
                ),
                std::ptr::null_mut::<libc::c_void>(),
            );
        }
    }
    unsafe {
        debug_return_int!(if strict { errors } else { 0 });
    }
}
unsafe extern "C" fn print_unused(
    mut parse_tree: *mut sudoers_parse_tree,
    mut a: *mut alias_struct,
    mut v: *mut libc::c_void,
) -> libc::c_int {
    fprintf(
        stderr,
        sudo_warn_gettext_v1(
            b"sudoers\0" as *const u8 as *const libc::c_char,
            b"Warning: %s:%d unused %s \"%s\"\0" as *const u8 as *const libc::c_char,
        ),
        (*a).file,
        (*a).lineno,
        alias_type_to_string((*a).type0 as libc::c_int),
        (*a).name,
    );
    fputc('\n' as i32, stderr);
    0 as libc::c_int
}

fn parse_sudoers_options() {
    let mut plugins: *mut plugin_info_list = std::ptr::null_mut::<plugin_info_list>();
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());
    }

    unsafe {
        plugins = sudo_conf_plugins_v1();
        if !plugins.is_null() {
            let mut info: *mut plugin_info = std::ptr::null_mut::<plugin_info>();
            info = (*plugins).tqh_first;
            while !info.is_null() {
                if strcmp(
                    (*info).symbol_name,
                    b"sudoers_policy\0" as *const u8 as *const libc::c_char,
                ) == 0 as libc::c_int
                {
                    break;
                }
                info = (*info).entries.tqe_next;
            }
            if !info.is_null() && !((*info).options).is_null() {
                let mut cur: *const *mut libc::c_char = std::ptr::null::<*mut libc::c_char>();
                cur = (*info).options;
                while !(*cur).is_null() {
                    let mut errstr: *const libc::c_char = std::ptr::null::<libc::c_char>();
                    let mut p: *const libc::c_char = std::ptr::null::<libc::c_char>();
                    let mut id: id_t = 0;

                    if MATCHES_VISUDO!(*cur, b"sudoers_file=\0", 14) {
                        sudoers_file = (*cur)
                            .offset(
                                ::core::mem::size_of::<[libc::c_char; 14]>() as libc::c_ulong
                                    as isize,
                            )
                            .offset(-(1 as libc::c_int as isize));
                        cur = cur.offset(1);
                        continue;
                    }
                    if MATCHES_VISUDO!(*cur, b"sudoers_uid=\0", 13) {
                        p = (*cur)
                            .offset(
                                ::core::mem::size_of::<[libc::c_char; 13]>() as libc::c_ulong
                                    as isize,
                            )
                            .offset(-(1 as libc::c_int as isize));
                        id = sudo_strtoid_v2(p, &mut errstr);
                        if errstr.is_null() {
                            sudoers_uid = id;
                        }
                        cur = cur.offset(1);
                        continue;
                    }

                    if MATCHES_VISUDO!(*cur, b"sudoers_gid=\0", 13) {
                        p = (*cur)
                            .offset(
                                ::core::mem::size_of::<[libc::c_char; 13]>() as libc::c_ulong
                                    as isize,
                            )
                            .offset(-(1 as libc::c_int as isize));
                        id = sudo_strtoid_v2(p, &mut errstr);
                        if errstr.is_null() {
                            sudoers_gid = id;
                        }
                        cur = cur.offset(1);
                        continue;
                    }

                    if MATCHES_VISUDO!(*cur, b"sudoers_mode=\0", 14) {
                        p = (*cur)
                            .offset(
                                ::core::mem::size_of::<[libc::c_char; 14]>() as libc::c_ulong
                                    as isize,
                            )
                            .offset(-(1 as libc::c_int as isize));
                        id = sudo_strtomode_v1(p, &mut errstr) as id_t;
                        if errstr.is_null() {
                            sudoers_mode = id;
                        }
                        cur = cur.offset(1);
                        continue;
                    }
                    cur = cur.offset(1);
                }
            }
        }
    }
    unsafe {
        debug_return!();
    }
}

/*
 * Unlink any sudoers temp files that remain.
 */
unsafe extern "C" fn visudo_cleanup() {
    let mut sp: *mut sudoersfile = std::ptr::null_mut::<sudoersfile>();
    sp = sudoerslist.tqh_first;
    while !sp.is_null() {
        if !((unsafe { *sp }).tpath).is_null() {
            unsafe { unlink((*sp).tpath) };
        }
        sp = (unsafe { *sp }).entries.tqe_next;
    }
}

/*
 * Unlink sudoers temp files (if any) and exit.
 */
unsafe extern "C" fn quit(mut signo: libc::c_int) {
    let mut sp: *mut sudoersfile = std::ptr::null_mut::<sudoersfile>();
    let mut iov: [iovec; 4] = [iovec {
        iov_base: std::ptr::null_mut::<libc::c_void>(),
        iov_len: 0,
    }; 4];
    sp = sudoerslist.tqh_first;
    while !sp.is_null() {
        if !((*sp).tpath).is_null() {
            unlink((*sp).tpath);
        }
        sp = (*sp).entries.tqe_next;
    }

    iov[0 as libc::c_int as usize].iov_base =
        sudo_getprogname() as *mut libc::c_char as *mut libc::c_void;
    iov[0 as libc::c_int as usize].iov_len =
        strlen(iov[0 as libc::c_int as usize].iov_base as *const libc::c_char);
    iov[1 as libc::c_int as usize].iov_base =
        b" exiting due to signal: \0" as *const u8 as *const libc::c_char as *mut libc::c_void;
    iov[1 as libc::c_int as usize].iov_len = (::core::mem::size_of::<[libc::c_char; 25]>()
        as libc::c_ulong)
        .wrapping_sub(1 as libc::c_int as libc::c_ulong);
    iov[2 as libc::c_int as usize].iov_base = strsignal(signo) as *mut libc::c_void;
    iov[2 as libc::c_int as usize].iov_len =
        strlen(iov[2 as libc::c_int as usize].iov_base as *const libc::c_char);
    iov[3 as libc::c_int as usize].iov_base =
        b"\n\0" as *const u8 as *const libc::c_char as *mut libc::c_void;
    iov[3 as libc::c_int as usize].iov_len = 1 as libc::c_int as size_t;
    let mut y: ssize_t = writev(2 as libc::c_int, iov.as_mut_ptr(), 4 as libc::c_int);
    _exit(signo);
}
fn usage(mut fatal: libc::c_int) {
    unsafe {
        fprintf(
            if fatal != 0 { stderr } else { stdout },
            b"usage: %s [-chqsV] [[-f] utsudoers ]\n\0" as *const u8 as *const libc::c_char,
            sudo_getprogname(),
        )
    };
    if fatal != 0 {
        unsafe { exit(1 as libc::c_int) };
    }
}
fn help() -> ! {
    //  let res = sudo_getprogname();
    //    println!("{:#?} - safely edit the sudoers file\n",sudo_getprogname());
    unsafe {
        printf(
            b"%s - safely edit the utsudoers file\n\n\0" as *const u8 as *const libc::c_char,
            sudo_getprogname(),
        )
    };
    usage(0 as libc::c_int);

    println!("\nOptions:");
    println!("  -c, --check              check-only mode");
    println!("  -f, --file=utsudoers     specify utsudoers file location");
    println!("  -h, --help               display help message and exit");
    println!("  -q, --quiet              less verbose (quiet) syntax error messages");
    println!("  -s, --strict             strict syntax checking");
    println!("  -V, --version            display version information and exit\n");

    unsafe { exit(0 as libc::c_int) };
}
pub fn main() {
    let mut args: Vec<*mut libc::c_char> = Vec::new();
    for arg in ::std::env::args() {
        args.push(
            (::std::ffi::CString::new(arg))
                .expect("Failed to convert argument into CString.")
                .into_raw(),
        );
    }
    args.push(::core::ptr::null_mut());
    unsafe {
        ::std::process::exit(main_0((args.len() - 1) as libc::c_int, args.as_mut_ptr()) as i32)
    }
}
unsafe extern "C" fn run_static_initializers() {
    sudoerslist = {
        sudoersfile_list {
            tqh_first: std::ptr::null_mut::<sudoersfile>(),
            tqh_last: &mut sudoerslist.tqh_first,
        }
        //init
    };
}
#[used]
#[cfg_attr(target_os = "linux", link_section = ".init_array")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XIB")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
static INIT_ARRAY: [unsafe extern "C" fn(); 1] = [run_static_initializers];
